// 路由
import Vue from "vue"
import VueRouter from 'vue-router'
import routes from './routes'
import store from '@/store'
Vue.use(VueRouter)

// 编程式导航点击多次路径没有发生变化跳转会报错，我们需要解决这个问题，
// 我们可以借鉴数组响应式的给数组七个方法实现响应式的方法给编程式导航的push和replace方法包装一下
// push和replace方法是VueRouter原型身上的方法

// 包装push方法
// 首先我们先把具有跳转功能的push方法缓存下来
let originPush = VueRouter.prototype.push
// 在VueRouter身上重新添加一个新的push方法覆盖之前的push方法，之后通过this.$router方法调用的push方法都是我们自己写的这个push方法
VueRouter.prototype.push = function (localtion, resolve, reject) {
    if (resolve === undefined && reject === undefined) {
        // 表示使用push方法时，一个回调函数都没有传递，就需要我们解决报错问题
        // 调用原来的push方法，使用catch方法处理报错
        // 我们需要将originPush里面的this改变为调用的路由器实例，因为之前是路由器实例调用的这方法
        // 我们自己的push方法是由路由器实例调用的，所以这个函数里面的this一定指向路由器实例，所以call方法中传递this就可以了
        // 原来的push方法调用之后会返回一个promise，所以我们键这个promise返回出去就可以了
        return originPush.call(this, localtion).catch(() => { })
    } else {
        // 表示使用push方法时，传递了一个或者两个回调函数,直接使用路由器实例调用原来的push方法返将接收到的回调函数传递，然后返回出去就可以了
        return originPush.call(this, localtion, resolve, reject)
    }
}
// 包装replace方法   同理push方法
// 首先我们先把具有跳转功能的push方法缓存下来
let originReplace = VueRouter.prototype.replace
VueRouter.prototype.replace = function (localtion, resolve, reject) {
    if (resolve === undefined && reject === undefined) {
        return originReplace.call(this, localtion).catch(() => { })
    } else {
        return originReplace.call(this, localtion, resolve, reject)
    }
}

const router = new VueRouter({
    routes,
    scrollBehavior() {//控制页面跳转滚动条的位置
        return {
            // x: 0,//控制x轴的滚动条   这里我们暂时用不上
            y: 0//控制y轴的滚动条
        }
    }
})

/* 
导航守卫
导航：路由正在发生变化
守卫：看门的(一个函数) 控制这能不能进入到某个路由或者强制进入到其他某个路由
导航守卫的分类：
    1.全局守卫：管的宽，项目中只要有路由就会经过它(全局守卫又分三个阶段：全局前置守卫、全局解析守卫、全局后置钩子)
    2.路由独享守卫：只有经过某个路由时才会执行
    3.单个组件守卫：只有经过某个路由组件时才会执行
*/
// 全局前置守卫(设置全局守卫的时候越早越好，所以一般使用全局前置守卫)
// 只要路由发生变化，就会经过这个全局前置守卫
router.beforeEach(async (to, from, next) => {
    /* 
    console.log(to,from);
    to  表示要去的路由对象
    from  表示来的那个路由对象
    next  是放行函数  不写默认不放行
    next()  //直接写next表示无条件放行
    next(false)  //表示不放行，路由跳转不过去
    next('/search')  //不管你要跳转到哪里去，全部给你跳转到search这个路由里面传参方式和push一样，这种方式一般要加判断才能使用，不然页面会一直跳转，超出最大栈内存调用 
    */

    // 使用导航守卫解决页面刷新用户信息丢失
    // 先获取token和userInfo
    let token = localStorage.getItem('token')
    let userInfo = store.state.user.userInfo
    if (token) {//有token证明登录了
        if (to.path === '/login') {
            next('/')
        } else {
            if (userInfo.name) {//vuex里面有用户信息
                next()//登陆了且有用户信息直接放行
            } else {//vuex里面的用户信息丢失了
                try {
                    const res = await store.dispatch('getUserInfo')
                    console.log('22');
                    // 成功获取数据就放行
                    next()
                } catch (error) {
                    // 没有获取到数据那么就是token失效了(为了安全起见，一般在七天左右后端就会重新更新一下每一个用户的token值)
                    // token失效就跳转到登录页面重新登录
                    await store.dispatch('getLoginOut')
                    next('/login')
                }
            }
        }
    } else {//没有token证明没有登录
        // 那么有些页面是可以进去的 首页 登录 注册 搜索 详情 购物车...
        // 也有一些是不能过去的  交易 支付 订单...
        // 之后完成了交易 支付 订单这些页面 再返回来处理这里 现在暂时无条件放行
        // trade pay paysuccess center center/myorder  center/grouporder 这六个页面没有登录是不可以进入的
        if (to.path.indexOf('/trade') !== -1 || to.path.indexOf('/pay') !== -1 || to.path.indexOf('/center') !== -1) {
            next('/login?wantpath=' + to.path)
        } else {
            next()
        }
    }
})

export default router